// Package controller 控制器的函数 包含gin的句柄
// 使用xorm作为数据库连接
package controller

import (
	"log"
	"net/http"
	"strconv"

	zjwt "ginbase/jwt"
	"ginbase/switcher/comm"
	sw2 "ginbase/switcher/switcherXorm"
	"ginbase/zConfig"

	"github.com/gin-contrib/cors"
	"github.com/gin-contrib/gzip"
	"github.com/gin-contrib/pprof"
	"github.com/gin-contrib/static"
	"github.com/gin-gonic/gin"
)

// 根据配置文件开启服务
func (ctrl *CTRLXorm)Server(cfg *zConfig.ServiceConfig) {
    s := make(chan int)
    // 开启单独执行insert update delete的子线程
    go func(cfg *zConfig.ServiceConfig) {
        // 连接数据库
        db := ConnectEngine(cfg.Database, "default")
        sw2.PipeExecSQL(db)
    }(cfg)
    // https服务需要的证书文件是否配置
    if "" != cfg.HTTPS.CertFile && "" != cfg.HTTPS.KeyFile {
        for _, ps := range cfg.HTTPS.Port {
            // 开启https服务
            go ctrl.serverHTTPS(cfg, strconv.Itoa(ps))
        }
    } else {
        // https服务需要的证书文件没有配置 http服务
        for _, p := range cfg.HTTP.Port {
            // 开启http服务
            go ctrl.serverHTTP(cfg, strconv.Itoa(p))
        }
    }
    <- s
}

// 根据配置文件开启http服务
func (ctrl *CTRLXorm)serverHTTP(cfg *zConfig.ServiceConfig, port string) {
    // 设置gin的路由定义和其他的东西
    router := ctrl.setServerRouter(cfg, port)
    // 启动服务
    router.Run(":" + port)
}

// 根据配置文件开启https服务
func (ctrl *CTRLXorm)serverHTTPS(cfg *zConfig.ServiceConfig, port string) {
    // 设置gin的路由定义和其他的东西
    router := ctrl.setServerRouter(cfg, port)
    // 启动服务
    router.RunTLS(":" + port, cfg.HTTPS.CertFile, cfg.HTTPS.KeyFile)
}

// 设置路由和其他东西
func (ctrl *CTRLXorm)setServerRouter(cfg *zConfig.ServiceConfig, port string) *gin.Engine {
    router := gin.Default()
    //    // 开启正式模式(默认是调试模式)
    //   gin.SetMode(gin.ReleaseMode)
    pprof.Register(router)
    
    // 开启gzip中间件
    router.Use(gzip.Gzip(gzip.DefaultCompression))
    // 开启默认跨域
    config := cors.DefaultConfig()
    config.AllowAllOrigins = true
    // ueditor 需要单独引入一个header
    config.AddAllowHeaders("x_requested_with")
    router.Use(cors.New(config))

    // 路由定义
    // 404 
    router.NoRoute(func (c *gin.Context)  {
        c.JSON(http.StatusNotFound, &Rtn{false, "404 Not Found", nil});
    })
    // 登陆/获取jwt token的路由 需要根据每个项目单独写
    router.GET("/login", zjwt.LoginHandler)
    router.POST("/login", zjwt.LoginHandler)
    // 路由组
    routerGroup := router.Group("/")
    // 根据配置文件中的设置 确定是否开启jwt token验证
    if cfg.Configs["activeJWT"] != JWTDeactived {
        routerGroup.Use(zjwt.JwtValidate())
    }
    // 路由组中的路由定义
    routerGroup.GET("/ping/:param", ctrl.pingHandler)
    routerGroup.GET("/api", ctrl.secondHanlder)
    routerGroup.POST("/api", ctrl.secondHanlder)
    routerGroup.GET("/api2", ctrl.thirdHandler)
    routerGroup.GET("/db4web", ctrl.db4webHanlder)
    routerGroup.POST("/db4web", ctrl.db4webHanlder)
    // 静态文件的路由
    router.Use(static.Serve("/", static.LocalFile("public", true)))
    return router
}

func (ctrl *CTRLXorm)pingHandler(c *gin.Context) {
    name := c.Param("param")
    c.String(http.StatusOK, "pong %s", name)
}

// 连接指定数据库的句柄
func (ctrl *CTRLXorm)secondHanlder(c *gin.Context) {
    // 调用接口的cmd
    cmd := comm.GetCMD(c)
    if "" == cmd {
        // 未传cmd 直接报错返回
        dataResponse(c, &Rtn{Success: false, Errmsg: "未传参数cmd", Data: nil})
        return
    }
    log.Printf("secondHanlder cmd:%s, method:%s, url:%s", cmd, c.Request.Method, c.Request.URL)
    // 连接数据库
    engine := ConnectEngine(ctrl.Cfg.Database, "default")
    // 异常情况处理
    defer ctrl.panicHanlderII(c, engine)

    // 调用cmd所指定的函数并获取返回值
    switcher := sw2.Dispatch(engine)
    var data interface{}
    var msg string
    if Authorize(c) {
        method := switcher[cmd]
        // 判断cmd对应的接口函数是否存在
        if nil == method {
            log.Panicf("未知接口:%s", cmd)
        } else {
            msg, data = method(c)
        }
    } else {
        log.Println("Not authorized!")
        panic("Not authorized!")
    }
    
    // 拼返回数据
    rtn := &Rtn{true, msg, data}
    // 返回请求的数据
    dataResponse(c, rtn)
}

// 连接全部数据库的句柄
func (ctrl *CTRLXorm)thirdHandler(c *gin.Context) {
    // 调用接口的cmd
    cmd := comm.GetCMD(c)
    if "" == cmd {
        // 未传cmd 直接报错返回
        dataResponse(c, &Rtn{Success: false, Errmsg: "未传参数cmd", Data: nil})
        return
    }
    log.Printf("thirdHandler cmd:%s, method:%s, url:%s", cmd, c.Request.Method, c.Request.URL)
    // 连接数据库
    engines := ConnectEngines(ctrl.Cfg.Database)
    // 异常情况处理
    defer ctrl.panicHanlder(c, engines)
    
    // 调用cmd所指定的函数并获取返回值
    switcher := sw2.Dispatch(engines[0])
    var data interface{}
    var msg string
    if Authorize(c) {
        method := switcher[cmd]
        // 判断cmd对应的接口函数是否存在
        if nil == method {
            log.Panicf("未知接口:%s", cmd)
        } else {
            msg, data = method(c)
        }
    } else {
        panic("Not authorized!")
    }

    // 拼返回数据
    rtn := &Rtn{true, msg, data}
    // 返回请求的数据
    dataResponse(c, rtn)
}

// db4w4b兼容的句柄
func (ctrl *CTRLXorm)db4webHanlder(c *gin.Context) {
    // 调用接口的cmd
    cmd := comm.GetCMD(c)
    if "" == cmd {
        // 未传cmd 直接报错返回
        dataResponse(c, &Rtn{Success: false, Errmsg: "未传参数cmd", Data: nil})
        return
    }
    log.Printf("db4webHanlder cmd:%s, method:%s, url:%s", cmd, c.Request.Method, c.Request.URL)
    
    // 连接数据库
    engine := ConnectEngine(ctrl.Cfg.Database, "default")
    // 异常情况处理
    defer ctrl.panicHanlderII(c, engine)
    // 根据cmd判断 调用哪个dispatch
    var switcher sw2.Xl
    // 调用db4web的dispatch 
    switcher = sw2.DB4webDispatch(engine)
    var data interface{}
    var msg string
    if Authorize(c) {
        method := switcher[cmd]
        // 判断cmd对应的接口函数是否存在
        if nil == method {
            log.Panicf("未知接口:%s", cmd)
        } else {
            msg, data = method(c)
        }
    } else {
        log.Println("Not authorized!")
        panic("Not authorized!")
    }
    
    // 拼返回数据
    rtn := &Rtn{true, msg, data}
    // 返回请求的数据
    dataResponse(c, rtn)
}